home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / ADVANCED / ENVMAP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  27.3 KB  |  1,196 lines

  1.  
  2. /* envmap.c - David Blythe, SGI */
  3.  
  4. /* Texture environment mapping demo. */
  5.  
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <math.h>
  9. #ifndef _WIN32
  10. #include <unistd.h>
  11. #else
  12. #define drand48() (((float) rand())/((float) RAND_MAX))
  13. #endif
  14. #include <string.h>
  15. #include <GL/glut.h>
  16. #include "texture.h"
  17.  
  18. #if defined(GL_VERSION_1_1)
  19. /* Routines called directly. */
  20. #elif defined(GL_EXT_texture_object) && defined(GL_EXT_copy_texture) && defined(GL_EXT_subtexture)
  21. #define glBindTexture(A,B)     glBindTextureEXT(A,B)
  22. #define glGenTextures(A,B)     glGenTexturesEXT(A,B)
  23. #define glDeleteTextures(A,B)  glDeleteTexturesEXT(A,B)
  24. #define glCopyTexSubImage2D(A,B,C,D,E,F,G,H) glCopyTexSubImage2DEXT(A,B,C,D,E,F,G,H)
  25. #else
  26. #define glBindTexture(A,B)
  27. #define glGenTextures(A,B)
  28. #define glDeleteTextures(A,B)
  29. #define glCopyTexSubImage2D(A,B,C,D,E,F,G,H)
  30. #endif
  31.  
  32. /* Some <math.h> files do not define M_PI... */
  33. #ifndef M_PI
  34. #define M_PI 3.14159265358979323846
  35. #endif
  36.  
  37. #define OB_CUBE    0
  38. #define OB_SPHERE  1
  39. #define OB_SQUARE  2
  40. #define OB_CYL     3
  41. #define OB_TORUS   4
  42. #define OB_HSPHERE 5
  43.  
  44. #define NOBJS 5
  45. #define TDRAW 10
  46.  
  47. #define LIST_BASE 100
  48. #define TOBJ_BASE 200
  49. #define TEXSIZE   256   /* default texture-size */
  50.  
  51. typedef struct _vector {
  52.   float x, y, z;
  53. } vector_t;
  54.  
  55. typedef struct _face {
  56.   char *filename;
  57.   unsigned *buf;
  58.   int width;
  59.   int height;
  60.   int components;
  61.   vector_t u, v, n, o;  /* plane equation */
  62.   float angle1;
  63.   vector_t axis1;       /* for rotation */
  64.   float angle2;
  65.   vector_t axis2;
  66. } face_t;
  67.  
  68. typedef struct _color {
  69.   float r, g, b;
  70. } color_t;
  71.  
  72. struct {                /* command-line options */
  73.   int use_spheremap;
  74.   char *spheremap_file;
  75.   int hw;
  76.   int size;
  77.   int samples;
  78.   int object;
  79.   char *outfile;
  80.   int tessellation;
  81. } opts = {
  82.  
  83.   0, 0, 0, TEXSIZE, 4, OB_TORUS, 0, 30
  84. };                      /* default settings */
  85.  
  86. void display(void);
  87. void init(void);
  88. void build_lists(void);
  89. unsigned *render_spheremap(int *width, int *height,
  90.   int *components, int doalloc);
  91.  
  92. /* strdup is actually not a standard ANSI C or POSIX routine
  93.    so implement a private one.  OpenVMS does not have a strdup; Linux's
  94.    standard libc doesn't declare strdup by default (unless BSD or SVID
  95.    interfaces are requested). */
  96. static char *
  97. stralloc(const char *string)
  98. {
  99.   char *copy;
  100.  
  101.   copy = malloc(strlen(string) + 1);
  102.   if (copy == NULL)
  103.     return NULL;
  104.   strcpy(copy, string);
  105.   return copy;
  106. }
  107.  
  108. void
  109. vadd(vector_t * a, vector_t * b, vector_t * sum)
  110. {
  111.   sum->x = a->x + b->x;
  112.   sum->y = a->y + b->y;
  113.   sum->z = a->z + b->z;
  114. }
  115.  
  116. void
  117. vsub(vector_t * a, vector_t * b, vector_t * diff)
  118. {
  119.   diff->x = a->x - b->x;
  120.   diff->y = a->y - b->y;
  121.   diff->z = a->z - b->z;
  122. }
  123.  
  124. void
  125. vscale(vector_t * v, float scale)
  126. {
  127.   v->x *= scale;
  128.   v->y *= scale;
  129.   v->z *= scale;
  130. }
  131.  
  132. float
  133. vdot(vector_t * u, vector_t * v)
  134. {
  135.   return (u->x * v->x + u->y * v->y + u->z * v->z);
  136. }
  137.  
  138. void
  139. vreflect(vector_t * axis, vector_t * v, vector_t * r)
  140. {
  141.   vector_t t = *axis;
  142.  
  143.   vscale(&t, 2 * vdot(axis, v));
  144.   vsub(&t, v, r);
  145. }
  146.  
  147. int
  148. intersect(vector_t * v)
  149. {
  150.   int f;
  151.   float x, y, z;
  152.  
  153.   x = fabs(v->x);
  154.   y = fabs(v->y);
  155.   z = fabs(v->z);
  156.   if (x >= y && x >= z)
  157.     f = (v->x > 0) ? 2 : 0;
  158.   else if (y >= x && y >= z)
  159.     f = (v->y > 0) ? 4 : 5;
  160.   else
  161.     f = (v->z > 0) ? 3 : 1;
  162.  
  163.   return f;
  164. }
  165.  
  166. face_t face[6] =
  167. {
  168.   {"00.rgb", 0, 0, 0, 0,
  169.     {0, 0, -1},
  170.     {0, 1, 0},
  171.     {-1, 0, 0},
  172.     {-0.5, -0.5, 0.5}, 90.0,
  173.     {0, 1, 0}, 0,
  174.     {0, 0, 0}},
  175.   {"01.rgb", 0, 0, 0, 0,
  176.     {1, 0, 0},
  177.     {0, 1, 0},
  178.     {0, 0, -1},
  179.     {-0.5, -0.5, -0.5}, 180.0,
  180.     {0, 1, 0}, 0,
  181.     {0, 0, 0}},
  182.   {"02.rgb", 0, 0, 0, 0,
  183.     {0, 0, 1},
  184.     {0, 1, 0},
  185.     {1, 0, 0},
  186.     {0.5, -0.5, -0.5}, 270.0,
  187.     {0, 1, 0}, 0,
  188.     {0, 0, 0}},
  189.   {"03.rgb", 0, 0, 0, 0,
  190.     {-1, 0, 0},
  191.     {0, 1, 0},
  192.     {0, 0, 1},
  193.     {0.5, -0.5, 0.5}, 0.0,
  194.     {0, 1, 0}, 0,
  195.     {0, 0, 0}},
  196.   {"04.rgb", 0, 0, 0, 0,
  197.     {1, 0, 0},
  198.     {0, 0, 1},
  199.     {0, 1, 0},
  200.     {-0.5, 0.5, -0.5}, 90.0,
  201.     {1, 0, 0}, 180.0,
  202.     {0, 1, 0}},
  203.   {"05.rgb", 0, 0, 0, 0,
  204.     {1, 0, 0},
  205.     {0, 0, -1},
  206.     {0, -1, 0},
  207.     {-0.5, -0.5, 0.5}, -90.0,
  208.     {1, 0, 0}, 180.0,
  209.     {0, 1, 0}}
  210. };
  211.  
  212. void
  213. sample(int facenum, float s, float t, color_t * c)
  214. {
  215.   face_t *f = &face[facenum];
  216.   int xpos, ypos;
  217.   unsigned char *p;
  218.  
  219.   xpos = s * f->width;
  220.   ypos = t * f->height;
  221.  
  222.   p = (unsigned char *) &f->buf[ypos * f->width + xpos];
  223.   c->r = p[0] / 255.0;
  224.   c->g = p[1] / 255.0;
  225.   c->b = p[2] / 255.0;
  226. }
  227.  
  228. unsigned *
  229. construct_spheremap(int *width, int *height,
  230.   int *components)
  231. {
  232.   int i, j, x, y, f;
  233.   unsigned *spheremap;
  234.   unsigned char *lptr;
  235.   int size = opts.size;
  236.   color_t c, texel;
  237.   vector_t v, r, p;
  238.   float s, t, temp, k;
  239.   int samples;
  240.  
  241.   /* Read in the 6 faces of the environment */
  242.   for (i = 0; i < 6; i++) {
  243.     face[i].buf = read_texture(face[i].filename, &face[i].width,
  244.       &face[i].height, &face[i].components);
  245.     if (!face[i].buf) {
  246.       fprintf(stderr, "Error: cannot load image %s\n", face[i].filename);
  247.       exit(1);
  248.     }
  249.   }
  250.  
  251.   *components = face[0].components;
  252.   *width = *height = size;
  253.   samples = opts.samples;
  254.  
  255.   spheremap = (unsigned *) malloc(size * size * sizeof(unsigned));
  256.   if (!spheremap) {
  257.     perror("malloc");
  258.     exit(1);
  259.   }
  260.   lptr = (unsigned char *) spheremap;
  261.  
  262.   /* Calculate sphere-map by rendering a perfectly reflective solid sphere. */
  263.  
  264.   for (y = 0; y < size; y++)
  265.     for (x = 0; x < size; x++) {
  266.  
  267.       texel.r = texel.g = texel.b = 0.0;
  268.       for (j = 0; j < samples; j++) {
  269.         s = (x + (float) drand48()) / size - 0.5;
  270.         t = (y + (float) drand48()) / size - 0.5;
  271.  
  272.         temp = s * s + t * t;
  273.         if (temp >= 0.25) {  /* point not on sphere */
  274.           c.r = c.g = c.b = 0;
  275.           continue;
  276.         }
  277.         /* get point on sphere */
  278.         p.x = s;
  279.         p.y = t;
  280.         p.z = sqrt(0.25 - temp);
  281.         vscale(&p, 2.0);
  282.         /* ray from infinity (eyepoint) to surface */
  283.         v.x = 0.0;
  284.         v.y = 0.0;
  285.         v.z = 1.0;
  286.  
  287.         /* get reflected ray */
  288.         vreflect(&p, &v, &r);
  289.  
  290.         /* Intersect reflected ray with cube */
  291.         f = intersect(&r);
  292.         k = vdot(&face[f].o, &face[f].n) / vdot(&r, &face[f].n);
  293.         vscale(&r, k);
  294.         vsub(&r, &face[f].o, &v);
  295.  
  296.         /* Get texture map-indices */
  297.         s = vdot(&v, &face[f].u);
  298.         t = vdot(&v, &face[f].v);
  299.  
  300.         /* Sample to get color */
  301.         sample(f, s, t, &c);
  302.  
  303.         texel.r += c.r;
  304.         texel.g += c.g;
  305.         texel.b += c.b;
  306.       }
  307.  
  308.       lptr[0] = 255 * texel.r / samples;
  309.       lptr[1] = 255 * texel.g / samples;
  310.       lptr[2] = 255 * texel.b / samples;
  311.       lptr[3] = 0xff;
  312.       lptr += 4;
  313.     }
  314.  
  315.   return (unsigned *) spheremap;
  316. }
  317.  
  318. void
  319. texture_init(void)
  320. {
  321.   unsigned *buf;
  322.   int width, height, components;
  323.   char filename[80];
  324.  
  325.   if (opts.use_spheremap) {
  326.     strcpy(filename, opts.spheremap_file);
  327.     buf = read_texture(filename, &width, &height, &components);
  328.     if (components == 3)
  329.       components++;
  330.     if (!buf) {
  331.       fprintf(stderr, "Error: cannot load image %s\n", filename);
  332.       exit(1);
  333.     }
  334.   } else {
  335.     buf = (opts.hw) ?
  336.       render_spheremap(&width, &height, &components, 1) :
  337.       construct_spheremap(&width, &height, &components);
  338.  
  339.     if (!buf) {
  340.       fprintf(stderr, "Error: Cannot construct spheremap\n");
  341.       exit(1);
  342.     }
  343.   }
  344.  
  345.   glBindTexture(GL_TEXTURE_2D, TOBJ_BASE + TDRAW);
  346.   glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
  347.   glEnable(GL_TEXTURE_2D);
  348.   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
  349.   gluBuild2DMipmaps(GL_TEXTURE_2D, components, width, height,
  350.     GL_RGBA, GL_UNSIGNED_BYTE, buf);
  351.  
  352.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  353.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  354.     GL_LINEAR_MIPMAP_LINEAR);
  355.  
  356.   glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
  357.   glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
  358.   glEnable(GL_TEXTURE_GEN_S);
  359.   glEnable(GL_TEXTURE_GEN_T);
  360.  
  361.   free(buf);
  362. }
  363.  
  364. void
  365. texture_init_from_spheremap(void)
  366. {
  367.   int w, h, components;
  368.  
  369.   render_spheremap(&w, &h, &components, 0);
  370.  
  371.   glReadBuffer(GL_BACK);
  372.   glBindTexture(GL_TEXTURE_2D, TOBJ_BASE + TDRAW);
  373.   glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h);
  374.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  375.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  376.  
  377.   glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
  378.   glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
  379.   glEnable(GL_TEXTURE_GEN_S);
  380.   glEnable(GL_TEXTURE_GEN_T);
  381. }
  382.  
  383. void
  384. parse(int argc, char *argv[])
  385. {
  386.   int i = 1;
  387.   char *usage =
  388.   "Usage: map [-size n] [-samples n] [-help] \n\
  389. \t[-sphere filename | -cubemap [0-5].rgb]\n\
  390. \n\
  391. \t-size n : specify size of sphere-map (when generated from cubemap)\n\
  392. \t-samples n : #samples to use per pixel of the spheremap\n\
  393. \t-sphere file.rgb  : specify spheremap-image\n\
  394. \t-cubemap [0-5].rgb: specify 6 cubemap files\n\
  395. \t-out file.rgb: save generated spheremap to file\n\
  396. \t-hw   : Use hardware texture mapping to create sphere-map\n\
  397. \t-help : print this message\n";
  398.  
  399. #define check_arg(i, n, str) \
  400.   if (argc < i+n) {       \
  401.     fprintf(stderr, "%s needs an argument\n", str);  \
  402.     fprintf(stderr, usage); \
  403.     exit(1); \
  404.   }
  405.  
  406.   while (i < argc) {
  407.     if (!strcmp(argv[i], "-size")) {
  408.       check_arg(i, 1, "-size");
  409.       opts.size = atoi(argv[++i]);
  410.  
  411.     } else if (!strcmp(argv[i], "-samples")) {
  412.       check_arg(i, 1, "-samples");
  413.       opts.samples = atoi(argv[++i]);
  414.  
  415.     } else if (!strcmp(argv[i], "-out")) {
  416.       check_arg(i, 1, "-out");
  417.       opts.outfile = stralloc(argv[++i]);
  418.  
  419.     } else if (!strcmp(argv[i], "-sphere")) {
  420.       opts.use_spheremap = 1;
  421.  
  422.     } else if (!strcmp(argv[i], "-cubemap")) {
  423.       int j;
  424.       check_arg(i, 6, "-cubemap");
  425.       for (j = 0; j < 6; j++)
  426.         face[j].filename = stralloc(argv[++i]);
  427.  
  428.     } else if (!strcmp(argv[i], "-help")) {
  429.       fprintf(stderr, usage);
  430.       exit(0);
  431.  
  432.     } else if (!strcmp(argv[i], "-hw")) {
  433.       opts.hw = 1;
  434.  
  435.     } else {
  436.       if (opts.use_spheremap && !opts.spheremap_file)
  437.         opts.spheremap_file = stralloc(argv[i]);
  438.       else {
  439.         fprintf(stderr, "Error: unrecognized option %s\n", argv[i]);
  440.         fprintf(stderr, usage);
  441.         exit(1);
  442.       }
  443.     }
  444.     i++;
  445.   }                     /* end-while */
  446. }
  447.  
  448. #ifdef use_copytex
  449. static int currwidth = TEXSIZE;
  450. static int currheight = TEXSIZE;
  451. #else
  452. static int currwidth = 400;
  453. static int currheight = 400;
  454. #endif
  455.  
  456. static int do_spheremap = 0, do_alloc = 0;
  457. static GLfloat rotv[] =
  458. {0., 0., 0.};
  459. static GLfloat rots[] =
  460. {0., 0., 0.};
  461. static GLfloat plane[4][3] =
  462. {
  463.   {1.0, -1.0, 0.0},
  464.   {1.0, 1.0, 0.0},
  465.   {-1.0, 1.0, 0.0},
  466.   {-1.0, -1.0, 0.0}
  467. };
  468.  
  469. static GLfloat cube[6][4][3] =
  470. {
  471.   {
  472.     {1.0, -1.0, -1.0},  /* counter-clockwise faces */
  473.     {-1.0, -1.0, -1.0},
  474.     {-1.0, 1.0, -1.0},
  475.     {1.0, 1.0, -1.0}
  476.   },
  477.   {
  478.     {1.0, -1.0, 1.0},
  479.     {1.0, -1.0, -1.0},
  480.     {1.0, 1.0, -1.0},
  481.     {1.0, 1.0, 1.0}
  482.   },
  483.   {
  484.     {-1.0, -1.0, 1.0},
  485.     {1.0, -1.0, 1.0},
  486.     {1.0, 1.0, 1.0},
  487.     {-1.0, 1.0, 1.0}
  488.   },
  489.   {
  490.     {-1.0, -1.0, -1.0},
  491.     {-1.0, -1.0, 1.0},
  492.     {-1.0, 1.0, 1.0},
  493.     {-1.0, 1.0, -1.0}
  494.   },
  495.   {
  496.     {1.0, 1.0, 1.0},
  497.     {1.0, 1.0, -1.0},
  498.     {-1.0, 1.0, -1.0},
  499.     {-1.0, 1.0, 1.0}
  500.   },
  501.   {
  502.     {1.0, -1.0, -1.0},
  503.     {1.0, -1.0, 1.0},
  504.     {-1.0, -1.0, 1.0},
  505.     {-1.0, -1.0, -1.0}
  506.   }
  507. };
  508.  
  509. static float norm[6][3] =
  510. {
  511.   {0.0, 0.0, -1.0},
  512.   {1.0, 0.0, 0.0},
  513.   {0.0, 0.0, 1.0},
  514.   {-1.0, 0.0, 0.0},
  515.   {0.0, 1.0, 0.0},
  516.   {0.0, -1.0, 0.0}
  517. };
  518.  
  519. void
  520. reshape(int w, int h)
  521. {
  522.   currwidth = w;
  523.   currheight = h;
  524.   glViewport(0, 0, w, h);
  525.   glMatrixMode(GL_PROJECTION);
  526.   glLoadIdentity();
  527.   gluPerspective(40.0, (GLfloat) w / (GLfloat) h, 1.0, 20.0);
  528.  
  529.   glMatrixMode(GL_MODELVIEW);
  530.   glLoadIdentity();
  531.   gluLookAt(0, 0, 6,
  532.     0, 0, 0,
  533.     0, 1, 0);
  534. }
  535.  
  536. /* ARGSUSED1 */
  537. void
  538. keys(unsigned char key, int x, int y)
  539. {
  540.   switch (key) {
  541.  
  542.   case 'o':            /* switch between objects */
  543.     opts.object = (opts.object + 1) % NOBJS;
  544.     glutPostRedisplay();
  545.     break;
  546.  
  547.   case '+':            /* change tessellation */
  548.     opts.tessellation += 2;
  549.     build_lists();
  550.     glutPostRedisplay();
  551.     break;
  552.  
  553.   case '-':
  554.     opts.tessellation -= 2;
  555.     if (opts.tessellation < 4)
  556.       opts.tessellation = 4;
  557.     build_lists();
  558.     glutPostRedisplay();
  559.     break;
  560.  
  561.   case 's':            /* toggle between spheremap generation */
  562.     /* mode and display mode */
  563.     do_spheremap ^= 1;
  564.     if (!do_spheremap)  /* switch back to normal mode */
  565.       do_alloc = 1;
  566.     glutPostRedisplay();
  567.     break;
  568.  
  569.   case 'h':
  570.   case 'H':
  571.     printf("\nKey functions\n");
  572.     printf("\to: switch objects\n");
  573.     printf("\ts: switch to spheremap generation mode\n");
  574.     printf("\t+: increase tessellation\n");
  575.     printf("\t-: decrease tessellation\n");
  576.     printf("\th: help\n");
  577.     printf("\tESC: quit\n");
  578.     printf("\tleft/right arrow-keys: Rotate around X axis\n");
  579.     printf("\tup/down arrow-keys: Rotate around Y axis\n");
  580.     printf("\tpage-up/pgdown arrow-keys: Rotate around Z axis\n");
  581.     break;
  582.  
  583.   case 27:
  584.     exit(0);
  585.   }
  586. }
  587.  
  588. /* ARGSUSED1 */
  589. void
  590. special_keys(int key, int x, int y)
  591. {
  592.   GLfloat *vect;
  593.  
  594.   if (do_spheremap)
  595.     vect = rots;
  596.   else
  597.     vect = rotv;
  598.  
  599.   switch (key) {
  600.   case GLUT_KEY_LEFT:
  601.     vect[1] -= 0.5;
  602.     glutPostRedisplay();
  603.     break;
  604.   case GLUT_KEY_RIGHT:
  605.     vect[1] += 0.5;
  606.     glutPostRedisplay();
  607.     break;
  608.   case GLUT_KEY_UP:
  609.     vect[0] -= 0.5;
  610.     glutPostRedisplay();
  611.     break;
  612.   case GLUT_KEY_DOWN:
  613.     vect[0] += 0.5;
  614.     glutPostRedisplay();
  615.     break;
  616.   case GLUT_KEY_PAGE_UP:
  617.     vect[2] -= 0.5;
  618.     glutPostRedisplay();
  619.     break;
  620.   case GLUT_KEY_PAGE_DOWN:
  621.     vect[2] += 0.5;
  622.     glutPostRedisplay();
  623.     break;
  624.   }
  625. }
  626.  
  627. /* Use mouse buttons to generate spheremap on the fly while the objects are
  628.    being displayed.  */
  629. static void
  630. motion(int x, int y)
  631. {
  632.   rots[1] = 180.0 * x / currwidth - 90.0;
  633.   rots[0] = 180.0 * y / currheight - 90.0;
  634. #ifdef use_copytex
  635.   if (!do_spheremap)
  636.     texture_init_from_spheremap();
  637. #endif
  638.   glutPostRedisplay();
  639. }
  640.  
  641. void
  642. menu(int value)
  643. {
  644.   keys((unsigned char) value, 0, 0);
  645. }
  646.  
  647. #if defined(GL_VERSION_1_1)
  648.  
  649. static int
  650. supportsOneDotOne(void)
  651. {
  652.   const char *version;
  653.   int major, minor;
  654.  
  655.   version = (char *) glGetString(GL_VERSION);
  656.   if (sscanf(version, "%d.%d", &major, &minor) == 2)
  657.     return major >= 1 && minor >= 1;
  658.   return 0;            /* OpenGL version string malformed! */
  659. }
  660.  
  661. #endif
  662.  
  663. int
  664. main(int argc, char *argv[])
  665. {
  666.   int hasExtendedTextures;
  667.  
  668.   parse(argc, argv);
  669.   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
  670.   glutInitWindowSize(currwidth, currheight);
  671.   glutCreateWindow("Environment map");
  672.  
  673. #if defined(GL_VERSION_1_1)
  674.   hasExtendedTextures = supportsOneDotOne();
  675.   if(!hasExtendedTextures) {
  676.     fprintf(stderr,
  677.       "envmap: This example requires OpenGL 1.1.\n");
  678.     exit(1);
  679.   }
  680. #elif defined(GL_EXT_texture_object) && defined(GL_EXT_copy_texture) && defined(GL_EXT_subtexture)
  681.   hasExtendedTextures = glutExtensionSupported("GL_EXT_subtexture")
  682.     && glutExtensionSupported("GL_EXT_texture_object")
  683.     && glutExtensionSupported("GL_EXT_copy_texture");
  684.   if(!hasExtendedTextures) {
  685.     fprintf(stderr,
  686.       "envmap: This example requires the OpenGL EXT_subtexture, EXT_texture_object, and EXT_copy_texture extensions.\n");
  687.     exit(1);
  688.   }
  689. #else
  690.   hasExtendedTextures = 0;
  691.   if(!hasExtendedTextures) {
  692.     fprintf(stderr,
  693.       "envmap: This example must be compiled with either OpenGL 1.1 or the OpenGL EXT_subtexture, EXT_texture_object, and EXT_copy_texture extensions.\n");
  694.     exit(1);
  695.   }
  696. #endif
  697.  
  698.   init();
  699.  
  700.   glutReshapeFunc(reshape);
  701.   glutKeyboardFunc(keys);
  702.   glutSpecialFunc(special_keys);
  703.   if (opts.hw)
  704.     glutMotionFunc(motion);
  705.   glutDisplayFunc(display);
  706.   glutCreateMenu(menu);
  707.   glutAddMenuEntry("Switch object", 'o');
  708.   glutAddMenuEntry("Up tessellation", '+');
  709.   glutAddMenuEntry("Lower tessellation", '-');
  710.   glutAddMenuEntry("Quit", 27);
  711.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  712.   glutMainLoop();
  713.   return 0;             /* ANSI C requires main to return int. */
  714. }
  715.  
  716. void
  717. build_cube(void)
  718. {
  719.   int i;
  720.  
  721.   glNewList(LIST_BASE + OB_CUBE, GL_COMPILE);
  722.   for (i = 0; i < 6; i++) {
  723.     glBegin(GL_QUADS);
  724.     glNormal3fv(norm[i]);
  725.     glVertex3fv(cube[i][0]);
  726.     glVertex3fv(cube[i][1]);
  727.     glVertex3fv(cube[i][2]);
  728.     glVertex3fv(cube[i][3]);
  729.     glEnd();
  730.   }
  731.   glEndList();
  732. }
  733.  
  734. void
  735. build_sphere(int tess)
  736. {
  737.   float r = 1.0, r1, r2, z1, z2;
  738.   float theta, phi;
  739.   int nlon = tess, nlat = tess;
  740.   int i, j;
  741.  
  742.   glNewList(LIST_BASE + OB_SPHERE, GL_COMPILE);
  743.   glBegin(GL_TRIANGLE_FAN);
  744.   theta = M_PI * 1.0 / nlat;
  745.   r2 = r * sin(theta);
  746.   z2 = r * cos(theta);
  747.   glNormal3f(0.0, 0.0, 1.0);
  748.   glVertex3f(0.0, 0.0, r);
  749.   for (j = 0, phi = 0.0; j <= nlon; j++, phi = 2 * M_PI * j / nlon) {
  750.     glNormal3f(r2 * cos(phi), r2 * sin(phi), z2);
  751.     glVertex3f(r2 * cos(phi), r2 * sin(phi), z2);  /* top */
  752.   }
  753.   glEnd();
  754.  
  755.   for (i = 2; i < nlat; i++) {
  756.     theta = M_PI * i / nlat;
  757.     r1 = r * sin(M_PI * (i - 1) / nlat);
  758.     z1 = r * cos(M_PI * (i - 1) / nlat);
  759.     r2 = r * sin(theta);
  760.     z2 = r * cos(theta);
  761.     glBegin(GL_QUAD_STRIP);
  762.     for (j = 0, phi = 0; j <= nlat; j++, phi = 2 * M_PI * j / nlon) {
  763.       glNormal3f(r1 * cos(phi), r1 * sin(phi), z1);
  764.       glVertex3f(r1 * cos(phi), r1 * sin(phi), z1);
  765.       glNormal3f(r2 * cos(phi), r2 * sin(phi), z2);
  766.       glVertex3f(r2 * cos(phi), r2 * sin(phi), z2);
  767.     }
  768.     glEnd();
  769.   }
  770.  
  771.   glBegin(GL_TRIANGLE_FAN);
  772.   theta = M_PI * (nlat - 1) / nlat;
  773.   r2 = r * sin(theta);
  774.   z2 = r * cos(theta);
  775.   glNormal3f(0.0, 0.0, -1.0);
  776.   glVertex3f(0.0, 0.0, -r);
  777.   for (j = nlon, phi = 0.0; j >= 0; j--, phi = 2 * M_PI * j / nlon) {
  778.     glNormal3f(r2 * cos(phi), r2 * sin(phi), z2);
  779.     glVertex3f(r2 * cos(phi), r2 * sin(phi), z2);  /* bottom */
  780.   }
  781.   glEnd();
  782.   glEndList();
  783. }
  784.  
  785. /* Same as above routine except that we use homogeneous co-ordinates. Each
  786.    component (including w) is multiplied by z */
  787. void
  788. build_special_sphere(int tess)
  789. {
  790.   float r = 1.0, r1, r2, z1, z2;
  791.   float theta, phi;
  792.   int nlon = tess, nlat = tess;
  793.   int i, j;
  794.  
  795.   glNewList(LIST_BASE + OB_HSPHERE, GL_COMPILE);
  796.   glBegin(GL_TRIANGLE_FAN);
  797.   theta = M_PI * 1.0 / nlat;
  798.   r2 = r * sin(theta);
  799.   z2 = r * cos(theta);
  800.   glNormal3f(0.0, 0.0, 1.0);
  801.   glVertex4f(0.0, 0.0, r * r, r);
  802.   for (j = 0, phi = 0.0; j <= nlon; j++, phi = 2 * M_PI * j / nlon) {
  803.     glNormal3f(r2 * cos(phi), r2 * sin(phi), z2);
  804.     glVertex4f(r2 * cos(phi) * z2, r2 * sin(phi) * z2, z2 * z2, z2);  /* top */
  805.   }
  806.   glEnd();
  807.  
  808.   for (i = 2; i < nlat; i++) {
  809.     theta = M_PI * i / nlat;
  810.     r1 = r * sin(M_PI * (i - 1) / nlat);
  811.     z1 = r * cos(M_PI * (i - 1) / nlat);
  812.     r2 = r * sin(theta);
  813.     z2 = r * cos(theta);
  814.  
  815.     if (fabs(z1) < 0.01 || fabs(z2) < 0.01)
  816.       break;
  817.  
  818.     glBegin(GL_QUAD_STRIP);
  819.     for (j = 0, phi = 0; j <= nlat; j++, phi = 2 * M_PI * j / nlon) {
  820.       glNormal3f(r1 * cos(phi), r1 * sin(phi), z1);
  821.       glVertex4f(r1 * cos(phi) * z1, r1 * sin(phi) * z1, z1 * z1, z1);
  822.       glNormal3f(r2 * cos(phi), r2 * sin(phi), z2);
  823.       glVertex4f(r2 * cos(phi) * z2, r2 * sin(phi) * z2, z2 * z2, z2);
  824.     }
  825.     glEnd();
  826.   }
  827.  
  828.   glBegin(GL_TRIANGLE_FAN);
  829.   theta = M_PI * (nlat - 1) / nlat;
  830.   r2 = r * sin(theta);
  831.   z2 = r * cos(theta);
  832.   glNormal3f(0.0, 0.0, -1.0);
  833.   glVertex4f(0.0, 0.0, -r * -r, -r);
  834.   for (j = nlon, phi = 0.0; j >= 0; j--, phi = 2 * M_PI * j / nlon) {
  835.     glNormal3f(r2 * cos(phi), r2 * sin(phi), z2);
  836.     glVertex4f(r2 * cos(phi) * z2, r2 * sin(phi) * z2, z2 * z2, z2);  /* bottom 
  837.  
  838.                                                                        */
  839.   }
  840.   glEnd();
  841.   glEndList();
  842. }
  843.  
  844. void
  845. build_square(void)
  846. {
  847.   glNewList(LIST_BASE + OB_SQUARE, GL_COMPILE);
  848.   glBegin(GL_POLYGON);
  849.   glNormal3f(0.0, 0.0, 1.0);
  850.   glVertex3fv(plane[0]);
  851.   glVertex3fv(plane[1]);
  852.   glVertex3fv(plane[2]);
  853.   glVertex3fv(plane[3]);
  854.   glEnd();
  855.   glEndList();
  856. }
  857.  
  858. void
  859. build_cylinder(int tess)
  860. {
  861.   int slices = tess, stacks = tess;
  862.   int i, j;
  863.   GLfloat phi, z1, r, z2;
  864.  
  865.   glNewList(LIST_BASE + OB_CYL, GL_COMPILE);
  866.   z1 = 2.0;
  867.   r = 1.0;
  868.   glBegin(GL_TRIANGLE_FAN);
  869.   glNormal3f(0.0, 0.0, 1.0);
  870.   glVertex3f(0.0, 0.0, z1);
  871.   for (i = 0; i <= slices; i++) {
  872.     phi = M_PI * 2.0 * i / slices;
  873.     glVertex3f(r * cos(phi), r * sin(phi), z1);
  874.   }
  875.   glEnd();
  876.  
  877.   for (i = 0, z2 = 0.0, z1 = 2.0 / stacks; i < stacks; i++) {
  878.     glBegin(GL_QUAD_STRIP);
  879.     for (j = 0, phi = 0; j <= slices; j++, phi = M_PI * 2.0 * j / slices) {
  880.       glNormal3f(r * cos(phi), r * sin(phi), 0);
  881.       glVertex3f(r * cos(phi), r * sin(phi), z1);
  882.       glVertex3f(r * cos(phi), r * sin(phi), z2);
  883.     }
  884.     glEnd();
  885.     z1 += 2.0 / stacks;
  886.     z2 += 2.0 / stacks;
  887.   }
  888.  
  889.   z2 = 0.0;
  890.   glBegin(GL_TRIANGLE_FAN);
  891.   glNormal3f(0.0, 0.0, -1.0);
  892.   glVertex3f(0.0, 0.0, z2);
  893.   for (i = slices; i >= 0; i--) {
  894.     phi = M_PI * 2.0 * i / slices;
  895.     glVertex3f(r * cos(phi), r * sin(phi), z2);
  896.   }
  897.   glEnd();
  898.   glEndList();
  899. }
  900.  
  901. void
  902. build_torus(int tess)
  903. {
  904.   int i, j, k, l;
  905.   int numg = 1.2 * tess;
  906.   int nums = tess;
  907.   GLfloat x, y, z;
  908.   GLfloat theta, phi;
  909.   const GLfloat twopi = 2.0 * M_PI;
  910.   const GLfloat rg = 2.0, rs = 1.0;
  911.  
  912.   glNewList(LIST_BASE + OB_TORUS, GL_COMPILE);
  913.   for (i = 0; i < numg; i++) {
  914.  
  915.     glBegin(GL_QUAD_STRIP);
  916.     for (j = 0; j <= nums; j++) {
  917.       phi = twopi * j / nums;
  918.  
  919.       for (k = 0; k <= 1; k++) {
  920.         l = (i + k) % numg;
  921.         theta = twopi * l / numg;
  922.  
  923.         glNormal3f(rs * cos(phi) * cos(theta),
  924.           rs * cos(phi) * sin(theta),
  925.           rs * sin(phi));
  926.  
  927.         x = (rg + rs * cos(phi)) * cos(theta);
  928.         y = (rg + rs * cos(phi)) * sin(theta);
  929.         z = rs * sin(phi);
  930.         glVertex3f(x, y, z);
  931.       }
  932.     }
  933.     glEnd();
  934.   }
  935.   glEndList();
  936. }
  937.  
  938. void
  939. display(void)
  940. {
  941.   static int once = 0;
  942.  
  943.   if (!once && opts.hw) {
  944.     texture_init();
  945.     once = 1;
  946.   }
  947.   if (do_spheremap || do_alloc) {
  948.     int w, h, comp;
  949.     if (do_alloc) {
  950.       texture_init();
  951.       do_alloc = 0;
  952.     } else
  953.       render_spheremap(&w, &h, &comp, 0);
  954.  
  955.   } else {
  956.  
  957.     glPushMatrix();
  958.     glBindTexture(GL_TEXTURE_2D, TOBJ_BASE + TDRAW);
  959.     glEnable(GL_DEPTH_TEST);
  960.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  961.     glRotatef(rotv[0], 1, 0, 0);
  962.     glRotatef(rotv[1], 0, 1, 0);
  963.     glRotatef(rotv[2], 0, 0, 1);
  964.  
  965.     switch (opts.object) {
  966.  
  967.     case OB_SQUARE:
  968.     case OB_CUBE:
  969.     case OB_SPHERE:
  970.       glCallList(LIST_BASE + opts.object);
  971.       break;
  972.  
  973.     case OB_CYL:
  974.       glTranslatef(0.0, 0.0, -1.0);
  975.       glCallList(LIST_BASE + OB_CYL);
  976.       break;
  977.  
  978.     case OB_TORUS:
  979.       glScalef(0.6, 0.6, 0.6);
  980.       glEnable(GL_NORMALIZE);
  981.       glCallList(LIST_BASE + OB_TORUS);
  982.       glDisable(GL_NORMALIZE);
  983.       break;
  984.  
  985.     default:
  986.       printf("Eh?\n");
  987.     }
  988.  
  989.     glLineWidth(2.0);
  990.     glDisable(GL_DEPTH_TEST);
  991.     glDisable(GL_TEXTURE_2D);
  992.     glBegin(GL_LINES);
  993.     glColor3f(1.0, 0.0, 0.0);
  994.     glVertex3f(0.0, 0.0, 0.0);
  995.     glVertex3f(4.0, 0.0, 0.0);
  996.  
  997.     glColor3f(0.0, 1.0, 0.0);
  998.     glVertex3f(0.0, 0.0, 0.0);
  999.     glVertex3f(0.0, 4.0, 0.0);
  1000.  
  1001.     glColor3f(1.0, 1.0, 1.0);
  1002.     glVertex3f(0.0, 0.0, 0.0);
  1003.     glVertex3f(0.0, 0.0, 4.0);
  1004.     glEnd();
  1005.     glEnable(GL_TEXTURE_2D);
  1006.     glEnable(GL_DEPTH_TEST);
  1007.     glPopMatrix();
  1008.   }
  1009.  
  1010.   glutSwapBuffers();
  1011. }
  1012.  
  1013. void
  1014. build_lists(void)
  1015. {
  1016.   build_square();
  1017.   build_cube();
  1018.   build_sphere(opts.tessellation);
  1019.   build_cylinder(opts.tessellation);
  1020.   build_torus(opts.tessellation);
  1021.   build_special_sphere(opts.tessellation + 10);
  1022. }
  1023.  
  1024. void
  1025. init(void)
  1026. {
  1027.   glEnable(GL_DEPTH_TEST);
  1028.   glEnable(GL_CULL_FACE);
  1029.  
  1030.   glClearColor(0.0, 0.0, 0.0, 1.0);
  1031.   build_lists();
  1032.   texture_init();
  1033. }
  1034.  
  1035. void
  1036. err(void)
  1037. {
  1038.   printf("error=%#x\n", glGetError());
  1039. }
  1040.  
  1041. /* Use projective textures to generate sphere-map */
  1042. unsigned *
  1043. render_spheremap(int *width, int *height,
  1044.   int *components, int doalloc)
  1045. {
  1046.   int i, j, k;
  1047.   GLfloat p[4];
  1048.   static unsigned *spheremap = NULL;
  1049.   static int texread_done = 0;
  1050.  
  1051.   if (!opts.hw)         /* shouldn't come here */
  1052.     return NULL;
  1053.  
  1054.   for (i = 0; i < 6; i++) {
  1055.     if (!texread_done) {
  1056.       face[i].buf = read_texture(face[i].filename, &face[i].width,
  1057.         &face[i].height, &face[i].components);
  1058.       if (!face[i].buf) {
  1059.         fprintf(stderr, "Error: cannot load image %s\n", face[i].filename);
  1060.         exit(1);
  1061.       }
  1062.       for (j = 0; j < face[i].height; j++)  /* texture border hack!! */
  1063.         for (k = 0; k < face[i].width; k++)
  1064.           if (j < 1 || k < 1 ||
  1065.             j > face[i].height - 2 || k > face[i].width - 2) {
  1066.             unsigned char *p = (unsigned char *) &face[i].buf[face[i].width * j + k];
  1067.             p[3] = 0;   /* zero out alpha */
  1068.           }
  1069.     }
  1070.     glBindTexture(GL_TEXTURE_2D, TOBJ_BASE + i);
  1071.     glEnable(GL_TEXTURE_2D);
  1072.     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1073.  
  1074.     glTexImage2D(GL_TEXTURE_2D, 0, 4,
  1075.       face[i].width, face[i].height, 0,
  1076.       GL_RGBA, GL_UNSIGNED_BYTE, face[i].buf);
  1077.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  1078.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  1079.  
  1080.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  1081.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  1082.  
  1083.     glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  1084.  
  1085.     p[0] = 2.0;
  1086.     p[1] = p[2] = p[3] = 0.0;  /* 2zx */
  1087.     glTexGenfv(GL_S, GL_OBJECT_PLANE, p);
  1088.  
  1089.     glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  1090.     p[0] = 0.0;
  1091.     p[1] = 2.0;
  1092.     p[2] = p[3] = 0.0;  /* 2zy */
  1093.     glTexGenfv(GL_T, GL_OBJECT_PLANE, p);
  1094.  
  1095.     glTexGenf(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  1096.     p[0] = p[1] = 0.0;
  1097.     p[2] = 0.0;
  1098.     p[3] = 2.0;         /* 2z */
  1099.     glTexGenfv(GL_R, GL_OBJECT_PLANE, p);
  1100.  
  1101.     glEnable(GL_TEXTURE_GEN_S);
  1102.     glEnable(GL_TEXTURE_GEN_T);
  1103.     glEnable(GL_TEXTURE_GEN_R);
  1104.   }
  1105.  
  1106.   texread_done = 1;
  1107.  
  1108.   glMatrixMode(GL_PROJECTION);
  1109.   glPushMatrix();
  1110.   glMatrixMode(GL_MODELVIEW);
  1111.   glPushMatrix();
  1112.   glMatrixMode(GL_TEXTURE);
  1113.   glPushMatrix();
  1114.  
  1115.   glColor4f(1.0, 1.0, 1.0, 1.0);
  1116.  
  1117.   /* Initialize sphere-map colors, and viewing transformations */
  1118.  
  1119.   glMatrixMode(GL_PROJECTION);
  1120.   glLoadIdentity();
  1121.   glOrtho(-1, 1, -1, 1, 1.0, 100);
  1122.   glMatrixMode(GL_MODELVIEW);
  1123.   glLoadIdentity();
  1124.   gluLookAt(0, 0, 6,
  1125.     0, 0, 0,
  1126.     0, 1, 0);
  1127.  
  1128.   glEnable(GL_DEPTH_TEST);
  1129.   glEnable(GL_CULL_FACE);
  1130.  
  1131.   glEnable(GL_BLEND);
  1132.   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1133.  
  1134.   glClearColor(0.0, 0.0, 0.0, 1.0);
  1135.   glClearDepth(1.0);
  1136.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  1137.  
  1138.   /* Look at the sphere from the chosen viewing direction and render the
  1139.      sphere at origin.  */
  1140.  
  1141.   for (i = 0; i < 6; i++) {  /* for all faces */
  1142.     glBindTexture(GL_TEXTURE_2D, TOBJ_BASE + i);
  1143.  
  1144.     glMatrixMode(GL_TEXTURE);
  1145.     glLoadIdentity();
  1146.     glScalef(0.5, 0.5, 1.0);
  1147.     glTranslatef(1.0, 1.0, 0.0);
  1148.     glFrustum(-1.01, 1.01, -1.01, 1.01, 1.0, 100.0);
  1149.     if (face[i].angle2 != 0.) {
  1150.       glRotatef(face[i].angle2,
  1151.         face[i].axis2.x, face[i].axis2.y, face[i].axis2.z);
  1152.     }
  1153.     glRotatef(face[i].angle1,
  1154.       face[i].axis1.x, face[i].axis1.y, face[i].axis1.z);
  1155.     glRotatef(rots[0], 1, 0, 0);
  1156.     glRotatef(rots[1], 0, 1, 0);
  1157.     glRotatef(rots[2], 0, 0, 1);
  1158.     glTranslatef(0.0, 0.0, -1.00);
  1159.  
  1160.     glMatrixMode(GL_MODELVIEW);
  1161.     glClear(GL_DEPTH_BUFFER_BIT);
  1162.     glCallList(LIST_BASE + OB_HSPHERE);
  1163.   }
  1164.  
  1165.   glDisable(GL_BLEND);
  1166.   glMatrixMode(GL_PROJECTION);
  1167.   glPopMatrix();
  1168.   glMatrixMode(GL_MODELVIEW);
  1169.   glPopMatrix();
  1170.   glMatrixMode(GL_TEXTURE);
  1171.   glPopMatrix();
  1172.   glMatrixMode(GL_MODELVIEW);
  1173.  
  1174.   if (doalloc) {
  1175.     /* read in current image and return it to be used as the spheremap */
  1176.     unsigned *temp;
  1177.  
  1178.     temp = (unsigned *)
  1179.       malloc(currwidth * currheight * sizeof(unsigned));
  1180.     spheremap = (unsigned *)
  1181.       malloc(opts.size * opts.size * sizeof(unsigned));
  1182.  
  1183.     glReadBuffer(GL_BACK);
  1184.     glReadPixels(0, 0, currwidth, currheight, GL_RGBA,
  1185.       GL_UNSIGNED_BYTE, temp);
  1186.     gluScaleImage(GL_RGBA,
  1187.       currwidth, currheight, GL_UNSIGNED_BYTE, temp,
  1188.       opts.size, opts.size, GL_UNSIGNED_BYTE, spheremap);
  1189.     free(temp);
  1190.   }
  1191.   *width = *height = opts.size;
  1192.   *components = 4;
  1193.   return (unsigned *) spheremap;
  1194. }
  1195.  
  1196.